package club.beimeng.demos.demo2021年6月1日;

/*
本解法主要用来描述二维dp的记录，在每一次遍历分组时，使用临时变量来记录最大值，而非直接覆盖
当然，复杂度比一维dp有所增加，此解法主要用来解决为什么不能直接使用以下公式的疑惑
dp[i][j] = Math.max(dp[i - 1][j],dp[i - 1][j - v] + w);
*/
import java.util.Scanner;

public class Four{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        int MAX = 101;
        int N = input.nextInt();
        int V = input.nextInt();
        int[][] vol = new int[MAX][MAX];
        int[][] val = new int[MAX][MAX];
        for(int i = 1; i < N + 1; i++){
            int num = input.nextInt();
            for(int j = 1; j < num + 1; j++){
                vol[i][j] = input.nextInt();
                val[i][j] = input.nextInt();
            }

        }
        input.close();
        int[][] dp = new int[N + 1][V + 1];
        for(int i = 1; i < N + 1; i++){
            for(int j = 1; j < V + 1; j++){
                // tmpMax用来记录该分组内本次循环的最大值，如果不设置该值，
                // 则会导致每次循环记录的是大于dp[i - 1][j]的最后一个满足条件的k的值，而不是最值
                int tmpMax = 0;
                // vol[i][k] != 0的目的是提前退出循环，因为给定的数组vo[][]是定长的，而有效的输入并不一定填满整个数组
                // 如果使用List<List<Integer>>，则可以直接使用.length()来作为循环的退出条件
                for(int k = 1; k < MAX && vol[i][k] != 0; k++){
                    if(j >= vol[i][k]){
                        dp[i][j] = Math.max(dp[i - 1][j],dp[i - 1][j - vol[i][k]] + val[i][k]);
                        tmpMax = tmpMax > dp[i][j]?tmpMax:dp[i][j];
                    }else{
                        dp[i][j] = dp[i - 1][j];
                    }
                }
                dp[i][j] = tmpMax > dp[i][j]?tmpMax:dp[i][j];
            }
        }
        System.out.println(dp[N][V]);
    }
}

/*
 *
 * @author Mr.Bao
 * @date
 */